
Type CalCoreTrack

	Field m_coreBoneId:Int
	Field m_keyframes:CalCoreKeyframe[]
	
	Method New()
	
		m_coreBoneId = -1
		m_keyframes = New CalCoreKeyframe[0]
	
	End Method
	
	Method Create:Byte()
		Return True
	End Method
	
	Method destroy()
		m_keyframes = New CalCoreKeyframe[0]	
	End Method

	Method getState:Byte(time:Float, translation:CalVector, rotation:CalQuaternion)
	
		Local coreKeyframeIdBefore:Int, coreKeyframeIdAfter:Int
	
		' get the key-frame after the requested time
		coreKeyframeIdAfter = getUpperBound(time)
	
		' check if the time is after the last key-frame
		If coreKeyframeIdAfter = m_keyframes.length Then
			' return the last key-frame state
			coreKeyframeIdAfter = coreKeyframeIdAfter - 1
			rotation.assign(m_keyframes[coreKeyframeIdAfter].GetRotation())
			translation.assignvector(m_keyframes[coreKeyframeIdAfter].getTranslation())
			Return True
		EndIf
	
		' check if the time is before the first key-frame
		If coreKeyframeIdAfter = 0 Then
			' return the first keyframe state
			rotation.assign(m_keyframes[coreKeyframeIdAfter].GetRotation())
			translation.assignvector(m_keyframes[coreKeyframeIdAfter].getTranslation())
			Return True
		EndIf
	
		' get the key-frame before the requested one
		coreKeyframeIdBefore = coreKeyframeIdAfter - 1
	
		' get the two key-frames
		Local coreKeyframeBefore:CalCoreKeyframe, coreKeyframeAfter:CalCoreKeyframe
		coreKeyframeBefore = m_keyframes[coreKeyframeIdBefore]
		coreKeyframeAfter = m_keyframes[coreKeyframeIdAfter]
	
		' calculate the blending factor between the two key-frame states
		Local blendFactor:Float = (time - coreKeyframeBefore.getTime()) / (coreKeyframeAfter.getTime() - coreKeyframeBefore.getTime())
	
	
		translation.assignvector(coreKeyframeBefore.getTranslation())
		translation.blend(blendFactor, coreKeyframeAfter.getTranslation())
	
		rotation.assign(coreKeyframeBefore.GetRotation())
		rotation.blend(blendFactor, coreKeyframeAfter.GetRotation())
	
		Return True		
		
	End Method
	
	Method getCoreBoneId:Int()
		Return m_coreBoneId
	End Method
	
	Method setCoreBoneId:Byte(coreBoneId:Int)
		If coreBoneId < 0 Then Return False
		m_coreBoneId = coreBoneId
		Return True
	End Method
	
	Method getCoreKeyframeCount:Int()
		Return m_keyframes.length
	End Method
	
	Method getCoreKeyframe:CalCoreKeyframe(index:Int)
		Return m_keyframes[index]
	End Method
	
	Method addCoreKeyframe:Byte(coreKeyframe:CalCoreKeyframe)
	
		m_keyframes = m_keyframes[..m_keyframes.length+1]'push(coreKeyframe)
		m_keyframes[m_keyframes.length-1] = coreKeyframe
		Local index:Int = m_keyframes.length- 1
		'Resort by time
		While index > 0 And m_keyframes[index].getTime() < m_keyframes[index-1].getTime()
		
			Local temp:CalCoreKeyframe = m_keyframes[index]
			m_keyframes[index] = m_keyframes[index - 1]
			m_keyframes[index - 1] = temp
			index=index-1
			
		Wend
	
		Return True		
	End Method

	Method removeCoreKeyFrame(index:Int)
	
		Local kf:CalCoreKeyframe[] = New CalCoreKeyframe[m_keyframes.length-1]
		Local pos:Int = 0
		For Local i:Int = 0 To m_keyframes.length-1
		
			If i <> index Then
				kf[pos] = m_keyframes[i]
				pos=pos+1
			EndIf
		
		Next
		m_keyframes = kf
	End Method
	
	
	Method scale(factor:Float)
		For Local keyframeId:Int = 0 To m_keyframes.length-1
			m_keyframes[keyframeId].getTranslation().multScalarLocal(factor)
		Next		
	End Method
	
	Method getUpperBound:Int(time:Float)
	
		Local LLower:Int = 0
		Local UUpper:Int = m_keyframes.length - 1
	
		While LLower < UUpper - 1
			Local middle:Int = (LLower + UUpper) Shr 1
	
			If time >= m_keyframes[middle].getTime() Then
				LLower = middle
			
			Else 
				UUpper = middle
			EndIf
		Wend
	
		Return UUpper		
	
	End Method

End Type
